home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 2
/
The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO
/
clang
/
dbread2.zip
/
DBREAD2.C
< prev
next >
Wrap
Text File
|
1992-01-08
|
16KB
|
497 lines
/* Opens a DBF file and gives some information about the structure */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <dos.h>
#include <errno.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#pragma pack(1)
/* Some dBASE constants */
#define VERSION "1.1c"
#define MAXFIELDS 255
#define DB3FDASIZE 32
#define DB2FDASIZE 16
#define DBF_VERSION_MASK 7
#define DB4_MEMO_MASK 8
#define ANY_MEMO_MASK 128
#define FINDFIRST _dos_findfirst
#define FINDNEXT _dos_findnext
#define SPLITPATH _splitpath
#define FULLPATH _fullpath
/* Define dBASE II header structure without including field
descriptor array, from "dBASE Power:.." book */
typedef struct
{
char first_byte;
int num_recs;
char last_upd_month;
char last_upd_day;
char last_upd_yr;
int rec_bytes;
} DB2_HEADER;
/* Define dBASE II field descriptor array, from "dBASE Power:..." */
typedef struct
{
char field_name[11];
char field_type;
char field_length;
int dloc;
char field_decimal;
} DB2_FDA;
/* Define dBASE III,IV header structure without including field
descriptor array, see page E-2 of the dBASE IV Language Reference */
typedef struct
{
unsigned char first_byte;
unsigned char last_upd_yr;
unsigned char last_upd_month;
unsigned char last_upd_day;
unsigned long num_recs;
unsigned int head_bytes;
unsigned int rec_bytes;
unsigned char reserved_1[2];
unsigned char incomplete;
unsigned char is_encrypted;
unsigned char reserved_for_lan[12];
unsigned char has_mdx;
unsigned char reserved_2[3];
} DB3_HEADER ;
/* Define structure for dBASE III,IV array of field descriptors,
see page E-3 of the dBASE IV Language Reference */
typedef struct {
unsigned char field_name[11];
unsigned char field_type; /* C D F L M N */
unsigned char reserved1[4];
unsigned char field_length; /* in binary */
unsigned char field_decimal; /* in binary */
unsigned char reserved2[2];
unsigned char work_area_id;
unsigned char reserved3[10];
unsigned char has_tag; /* 01H if has tag in production MDX, 00H if not */
} DB3_FDA;
union DBF_HEADER
{
DB2_HEADER db2;
DB3_HEADER db3;
} in_header;
union DBF_FDA
{
DB2_FDA db2;
DB3_FDA db3;
} fd_array[ MAXFIELDS + 1 ];
void FullName( char *fileName, char *fileExt );
void db3_stru_read( void );
void db3_stru_list( void );
void db2_stru_read( void );
void db2_stru_list( void );
void arg_to_valid_path( char *arg, char *destination, char *default_ext );
int valid_db2( DB2_HEADER *header );
int valid_db3( DB3_HEADER *header );
/* Structure for file information. Used by _dos_findfirst, _dos_findnext */
struct find_t file_info;
/* struct find_t
{ // File information return structure
char reserved [21]; // Reserved for use by DOS
char attrib; // Attribute byte for matched path
unsigned wr_time; // Time of last write to file
unsigned wr_date; // Date of last write to file
long size; // Length of file in bytes
char name [13]; // Null-terminated name of matched
// file/directory, without the path
};
*/
/* String for input file name */
char input_file[_MAX_PATH];
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
unsigned char dbf_version;
int input_handle, field_counter, dbf_count = 0;
void main( int argc, char *argv[] )
{
/* Make sure there was at least one command line argument besides
program name */
if( argc < 2 )
{
printf( "\nDBRead version %s by Martin R. León\n\n"\
"Missing command line argument.\n"\
"USAGE:\tDBREAD <DBF file name>\n\n"\
"File name may include a drive and wildcard specifications.\n",
VERSION );
return;
}
arg_to_valid_path( argv[1], input_file, ".DBF" );
/* Now that we have all the path components in input_file, split it out
to individual components again */
SPLITPATH( input_file, drive, dir, fname, ext );
/* Check for a file specification that matches the one specified on
command line */
if( FINDFIRST( input_file, _A_RDONLY | _A_SYSTEM | _A_HIDDEN, &file_info ))
{
/* If none found, try adding DBF extension */
FullName( input_file, "DBF" );
if( FINDFIRST( input_file, _A_RDONLY | _A_SYSTEM | _A_HIDDEN, &file_info ))
{
/* Didn't find any matching files, show error and abandon */
printf( "\nNo files found matching %s\n", input_file );
return;
}
}
printf( "\nDBRead version %s by Martin R. León\n", VERSION );
/* Show structure information for all files that meet the file
specification indicated on command line */
do
{
/* Create new input file name from original drive and directory
and add file name resulting from the most recent FINDFIRST or
FINDNEXT calls */
strcpy( input_file, drive );
strcat( input_file, dir );
strcat( input_file, file_info.name );
/* Open file for read-only in binary mode and make sure there are
no errors openning it */
if((input_handle = open(input_file, O_RDONLY | O_BINARY, S_IREAD)) == -1)
{
printf( "\nUnable to open file %s\n", input_file );
continue;
}
/* Read record header to in_header and check for error */
if( read( input_handle, &in_header, sizeof(in_header) ) == -1 )
{
printf( "\nError reading header from file!\n" );
if( close( input_handle ) != 0 )
printf( "\nError closing file!\n" );
else
printf( "\nFile closed!\n" );
return;
}
/* Move file pointer back to beginning */
lseek( input_handle, 0, SEEK_SET );
/* Try to validate as a DB2 DBF file */
if( valid_db2( &in_header.db2 ) )
{
/* This is probably a good DB2 file, read the structure & list it */
db2_stru_read();
db2_stru_list();
dbf_count++;
}
else
/* Try to validate as a dB III/IV DBF file */
if( valid_db3( &in_header.db3 ) )
{
/* This is probably a good DB III/IV file, read structure & list it */
db3_stru_read();
db3_stru_list();
dbf_count++;
}
else
/* If this file has an extension that should contain a valid DBF but
the header is unreadable, display message. */
if(strstr( input_file, ".DBF" ) || strstr( input_file, ".DBK" ) ||
strstr( input_file, ".DBB" ) || strstr( input_file, ".CRP" ) ||
strstr( input_file, ".CVT" ) || strstr( input_file, ".CAT" ) ||
!(strstr( fname, "*") || strstr( fname, "?" )) ||
!(strstr( ext, "*") || strstr( ext, "?" )) )
printf( "\n%s is not a valid DBF file.\n", input_file );
/* Close file */
if( close( input_handle ) != 0 )
printf( "\nError closing file!\n" );
/* Go until no more files meet file specification from command line */
} while( !FINDNEXT( &file_info ) );
if( !dbf_count )
printf( "\nNo valid DBF structures found in %s%s%s%s\n",
drive, dir, fname, ext );
exit( 0 );
}
void db3_stru_read( void )
{
/* Read rest of header */
read( input_handle, &in_header.db3, (sizeof( in_header.db3 )) );
/* Read in field descriptor array. Read first field descriptor array
then go into for loop until 0DH is read into the field name. */
read( input_handle, &fd_array[1].db3, DB3FDASIZE );
for( field_counter = 1; field_counter <= MAXFIELDS; field_counter++ )
{
if( fd_array[ field_counter ].db3.field_name[ 0 ] == 0x0D )
{
field_counter--;
break;
}
read( input_handle, &fd_array[field_counter + 1].db3, DB3FDASIZE );
}
}
void db3_stru_list( void )
{
int x;
/* Print out header information */
printf( "\nDatabase name: %s\n"\
"DBF version: %d Any Memo's ? %c\t\n"\
"dBASE IV Memo ? %c Last Update: %d/%d/%d\n"\
"Number of records: %10ld Bytes per record: %u\n"\
"Encrypted ? %c MDX ? %c\n",
input_file,
in_header.db3.first_byte & DBF_VERSION_MASK,
((in_header.db3.first_byte & ANY_MEMO_MASK) ? 'Y' : 'N' ),
((in_header.db3.first_byte & DB4_MEMO_MASK) ? 'Y' : 'N' ),
in_header.db3.last_upd_month,
in_header.db3.last_upd_day,
in_header.db3.last_upd_yr,
in_header.db3.num_recs,
in_header.db3.rec_bytes,
(in_header.db3.is_encrypted) ? 'Y' : 'N',
(in_header.db3.has_mdx) ? 'Y' : 'N' );
/* If the file is encrypted, we can't read the structure, so don't try */
if( in_header.db3.is_encrypted )
return;
/* Print out field information */
if( in_header.db3.has_mdx )
printf( "\nField name\tType\tLen\tDec\tMDX\n\n" );
else
printf( "\nField name\tType\tLen\tDec\n\n" );
for( x = 1; x <= field_counter; x++ )
{
printf( "%-10s\t%c\t%d\t",
fd_array[ x ].db3.field_name,
fd_array[ x ].db3.field_type,
fd_array[ x ].db3.field_length );
if( fd_array[ x ].db3.field_type == 'N' )
printf( "%d\t", fd_array[ x ].db3.field_decimal );
else
printf( "\t" );
if( in_header.db3.has_mdx )
printf( "%c\n", ((fd_array[ x ].db3.has_tag) ? 'Y' : 'N') );
else
printf( "\n" );
}
return;
}
void db2_stru_read( void )
{
/* Read rest of header */
read( input_handle, &in_header.db2, (sizeof( in_header.db2 )) );
/* Read in field descriptor array. Read first field descriptor array
then go into for loop until 0DH is read into the field name. */
read( input_handle, &fd_array[1].db2, DB2FDASIZE );
for( field_counter = 1; field_counter <= MAXFIELDS; field_counter++ )
{
if( fd_array[ field_counter ].db2.field_name[ 0 ] == 0x0D )
{
field_counter--;
break;
}
read( input_handle, &fd_array[field_counter + 1].db2, DB2FDASIZE );
}
}
void db2_stru_list( void )
{
int x;
/* Print out header information */
printf( "\nDatabase name: %s\n"\
"DBF version: %d Last Update: %d/%d/%d\n"\
"Number of records: %10d Bytes per record: %i\n",
input_file,
in_header.db2.first_byte & DBF_VERSION_MASK,
in_header.db2.last_upd_month,
in_header.db2.last_upd_day,
in_header.db2.last_upd_yr,
in_header.db2.num_recs,
in_header.db2.rec_bytes );
printf( "\nField name\tType\tLen\tDec\n\n" );
for( x = 1; x <= field_counter; x++ )
{
printf( "%-10s\t%c\t%d\t",
fd_array[ x ].db2.field_name,
fd_array[ x ].db2.field_type,
fd_array[ x ].db2.field_length );
if( fd_array[ x ].db2.field_type == 'N' )
printf( "%d\n", fd_array[ x ].db2.field_decimal );
else
printf( "\n" );
}
return;
}
int valid_db2( DB2_HEADER *header )
{
return ( ((header->first_byte & DBF_VERSION_MASK) == 2) &&
(header->num_recs >= 0 && header->num_recs <= 65534) &&
(header->rec_bytes >=2 && header->rec_bytes <= 1000) &&
header->last_upd_month > 0 && header->last_upd_month <= 12 &&
header->last_upd_day > 0 && header->last_upd_day <=31 &&
header->last_upd_yr > 0);
}
int valid_db3( DB3_HEADER *header )
{
return (((header->first_byte & DBF_VERSION_MASK) == 3) &&
(header->rec_bytes >= 2 && header->rec_bytes <= 4000) &&
(header->head_bytes >= 63 && header->head_bytes <= 8193 ) &&
(header->num_recs >= 0 && header->num_recs < 100000000) );
}
/* Adds an extension to a string containing a file name if the specified
extension isn't already in the string. String must be larger than the
combination of the existing string and the extension to be added.
All done through pointer to original string. */
void FullName( char *fileName, char *fileExt )
{
/* Set ptr to last character before terminator in fiel name */
char *ptr = fileName + ( strlen( fileName ) - 1 );
/* Check for extension already in name */
if( strstr( fileName, fileExt ) != NULL )
return;
/* Extension wasn't found, back up ptr to first non-alpha character,
stop if we got to beginning of string */
while( isalpha( (int)*ptr ) )
{
if( --ptr == fileName )
break;
}
/* If we backed up to a slash, add ".DBF" to the end of the file name
and return */
if( *ptr == '\\' )
{
fileName = strcat( fileName, ".DBF" );
return;
}
/* If we backed up to a period, asterisk or ?, return without adding
extension */
if( *ptr == '.' || *ptr == '*' || *ptr == '?' )
return;
/* Add extension, since it wasn't found */
strcat( fileName, ".DBF" );
return;
}
/* A function to take a filespec including wildcards, . and .. to produce
a full proper absolute file path, adding a specified default extension is
no extension was specified. Assumes drive, dir, fname, ext are
global public strings as defined for _splitpath(). destination
string should be _MAX_PATH long. Resulting file path is stored in the string
pointed to by destination. drive, dir, fname, and ext receive the
appropriate components of the resulting file path.*/
void arg_to_valid_path( char *arg, char *destination, char *default_ext )
{
char temp_path[ _MAX_PATH ];
*destination = '\0';
/* Create a full file path specification */
strcpy( destination, strupr(arg) );
if( strcmp( destination + (strlen( destination ) - 2), ".." ) == 0 )
{
strcat( destination, "\\*" );
strcat( destination, default_ext );
}
temp_path[0] = '\0';
/* Break command line argument into path components. This first time
may not yield a file name or extension and the dir component may not
yield a complete absolute directory reference. */
SPLITPATH( destination, drive, dir, fname, ext );
/* Add drive to directory so that we can get a complete absolute directory
name */
strcpy( destination, drive );
strcat( destination, dir );
strcpy( dir, destination );
/* Expand drive/path specification to absolute directory name */
FULLPATH( temp_path, dir, _MAX_PATH );
/* If just the drive letter was specified, default to default extension */
if( strlen( drive ) && !strlen( fname ) && !strlen( ext ) )
{
strcpy( fname, "*" );
strcat( ext, default_ext );
}
/* If a lone period was specified, convert to default extension */
if( !strlen( fname ) && strcmp( ext, "." ) == 0 )
{
strcpy( fname, "*" );
strcat( ext, default_ext + 1 );
}
/* If a lone asterisk was specified, do the same as above. This is
slightly different because extension has no period */
if( strcmp( fname, "*" ) == 0 && !strlen( ext ) )
{
strcpy( fname, "*" );
strcat( ext, default_ext );
}
/* If a file name was specified but no extension, assume default extension */
if( strlen( fname ) && strcmp( fname, "*" ) != 0 && !strlen( ext ) )
strcat( ext, default_ext );
/* If there is a file name but no extension, use default extension */
if( !strlen( ext ) )
strcat( ext, default_ext );
/* Construct absolute input file name from path components */
strcpy( destination, strupr( temp_path ));
if( destination[ strlen( destination ) - 1 ] != '\\' )
strcat( destination, "\\" );
if( strlen( fname ) == 0 )
strcat( destination, "*" );
else
strcat( destination, fname );
if( strlen( ext ) == 0 )
strcat( ext, default_ext );
else
strcat( destination, ext );
}